package fsmsim.gui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.event.MouseInputListener;

import fsmsim.kernel.Estado;
import fsmsim.kernel.FSM;
import fsmsim.kernel.Transicion;

public class FSMPanel extends JPanel{

	/**
	 * 
	 */
	private static final long serialVersionUID = -7515690830867801058L;
	FSM _fsm;
	ControladorMouse _cm;
	
	JPopupMenu _menu;
	JMenuItem _mnuNuevoEstado;
	JMenuItem _mnuEliminarEstado;
	JMenuItem _mnuEliminarTransicion;
	JCheckBoxMenuItem _mnuCambiarFinal;
	JCheckBoxMenuItem _mnuCambiarInicial;
	JMenu _mnuPropiedadesEstado;
	
	BufferedImage _img;
	Graphics2D _g;
	
	Estado _selectEstado;
	Transicion _selectTransicion;
	
	
	public FSMPanel(FSM fsm){
		super();
		
		_cm=new  ControladorMouse();
		this.addMouseListener(_cm);
		this.addMouseMotionListener(_cm);
		_menu=new JPopupMenu();
		_menu.add(_mnuNuevoEstado=new JMenuItem("Nuevo estado"));
		_mnuNuevoEstado.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				String x= JOptionPane.showInputDialog(null, "Dame el nombre del nuevo estado", "Nuevo estado", JOptionPane.OK_CANCEL_OPTION);
				if(x!=null){
					if(x.length()>0){
						_fsm.addEstado(x,_cm._lastPunto);
						repintar(true);
					}
				}
			}
		});
		_menu.add(_mnuEliminarEstado=new JMenuItem("Eliminar estado"));
		
		_mnuEliminarEstado.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				if(_selectEstado!=null){
					_fsm.rmEstado(_selectEstado);
					repintar(true);
				}
			}
		});
		_menu.add(_mnuEliminarTransicion=new JMenuItem("Eliminar transicion"));
		_mnuEliminarTransicion.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				if(_selectTransicion!=null){
					_fsm.rmTransicion(_selectTransicion);
					repintar(true);
				}
			}
		});
		_menu.add(_mnuPropiedadesEstado=new JMenu(""));
		_mnuPropiedadesEstado.add(_mnuCambiarInicial=new JCheckBoxMenuItem("Inicial") );
		_mnuPropiedadesEstado.add(_mnuCambiarFinal=new JCheckBoxMenuItem("Final"));
		_mnuCambiarInicial.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if(_selectEstado!=null){
					_fsm.setInicial(_selectEstado);
					repintar(true);
				}
			}
		});
		_mnuCambiarFinal.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if(_selectEstado!=null){
					try{
						if(_selectEstado.isFinal()) _fsm.setEstadoFinal(_selectEstado, false);
						else _fsm.setEstadoFinal(_selectEstado, true);
					}catch(RuntimeException re){
						JOptionPane.showMessageDialog(FSMPanel.this, re.getMessage());
					}
					repintar(true);
				}
			}
		});
		setFSM(fsm);
	}
	public void setFSM(FSM fsm){
		_fsm=fsm;
		if(_fsm!=null){
			setPreferredSize(_fsm.getDimension());
			_img=new  BufferedImage(_fsm.getAncho() , _fsm.getAlto(), BufferedImage.OPAQUE);
			_g= _img.createGraphics();
			repintar();
		}
	}
	public FSM getFSM(){
		return _fsm;
	}
	private void repintar(){
		repintar(false);
	}
	private void repintar(boolean repaint){
		_g.setColor(Color.WHITE);
		_g.fillRect(0, 0, _img.getWidth(), _img.getHeight());
		ArrayList<Estado> edos= _fsm.getEstados();
		for(Estado e:edos){
			ArrayList<Transicion> trans= e.getTransiciones();
			for(Transicion t:trans)
				t.Draw(_g);
		}
		for(Estado e:edos)
			e.Draw(_g);
		if(repaint)
			this.repaint();
	}
	@Override
	public void paint(Graphics g){
		super.paint(g);
		if(_fsm!=null){
			g.drawImage(_img, 0, 0, this);
			if(_cm._newTransicion){
				g.setColor(Color.BLACK);
				g.drawLine(_selectEstado.getX(), _selectEstado.getY(), _cm._lastPunto.x, _cm._lastPunto.y);
			}else if(_cm._dragTransicion){
				_selectTransicion.Draw((Graphics2D) g, Color.RED, Color.BLACK);
			}
		}
	}
	
	class ControladorMouse implements MouseInputListener{
		Point _lastPunto;
		
		boolean _dragEstado;
		boolean _newTransicion;
		boolean _dragTransicion;
		@Override
		public void mouseClicked(MouseEvent e) {
			
		}

		@Override
		public void mouseEntered(MouseEvent e) {
			
		}

		@Override
		public void mouseExited(MouseEvent e) {
			
		}

		@Override
		public void mousePressed(MouseEvent e) {
			if(DisplayMenu(e)) return;
			
			if(e.getButton()== MouseEvent.BUTTON1){
				Object el=_fsm.getElemento(e.getPoint());
				if(el instanceof Estado){
					_selectEstado= (Estado) el;
					_selectTransicion = null;
				}else if(el instanceof Transicion){
					_selectEstado=null;
					_selectTransicion=(Transicion) el;
				}
				if(e.isControlDown()){
					if(_selectEstado!=null) _newTransicion=true;
				}else{
					if(_selectEstado!=null )_dragEstado=true;
					if(_selectTransicion!=null) _dragTransicion=true;
				}
			}
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			if(DisplayMenu(e)) return;
			if(_dragEstado){ 
				_dragEstado=false;
				_selectEstado.updatePosicion();
				_selectEstado =null;
				repintar(true);
			}
			if(_newTransicion){
				_newTransicion=false;
				Estado destino= _fsm.getEstado(e.getPoint());
				if(destino!=null){
					String r= JOptionPane.showInputDialog(FSMPanel.this, "Dame la regla para la transicion", "Nueva transicion", JOptionPane.QUESTION_MESSAGE);
					if(r!=null){
						_fsm.addTransicion(_selectEstado, destino, r);
					}
				}
				repintar(true);
				_selectEstado=null;
				
			}if(_dragTransicion){
				_dragTransicion =false;
				_selectTransicion=null;
				repintar(true);
			}
		}

		@Override
		public void mouseDragged(MouseEvent e) {
			if(_dragEstado){
				_selectEstado.chPosicion(e.getPoint());
				_selectEstado.updatePosicion();
				repintar(true);
			}
			if(_newTransicion) {
				_lastPunto=e.getPoint();
				repaint();
			}
			if(_dragTransicion){
				_selectTransicion.updateLocation(e.getPoint());
				// TODO : Quiza se quiera mandar a llamar el metodo repitar(true)
				repaint();
			}
			
		}

		@Override
		public void mouseMoved(MouseEvent e) {
			
		}
		
		private boolean  DisplayMenu(MouseEvent e){
			if( e.isPopupTrigger()){
				_lastPunto= e.getPoint();
				Object el=_fsm.getElemento(_lastPunto);
				if( el instanceof Estado){
					_selectEstado= (Estado) el;
					_selectTransicion=null;
				}else{
					_selectTransicion= (Transicion) el;
					_selectEstado=null;
				}
				if(_selectEstado!=null){
					_mnuEliminarEstado.setVisible(true);
					_mnuPropiedadesEstado.setVisible(true);
					_mnuEliminarTransicion.setVisible(false);
					_mnuEliminarEstado.setText("Eliminar estado: "+_selectEstado.getNombre());
					_mnuPropiedadesEstado.setText("Propiedades de \""+_selectEstado.getNombre()+"\"");
					_mnuCambiarInicial.setSelected( _selectEstado.isInicial()  );
					_mnuCambiarFinal.setSelected(_selectEstado.isFinal());
					_mnuCambiarInicial.setEnabled(!_selectEstado.isInicial());
				}else if(_selectTransicion!=null){
					_mnuEliminarEstado.setVisible(false);
					_mnuPropiedadesEstado.setVisible(false);
					_mnuEliminarTransicion.setVisible(true);
					_mnuEliminarTransicion.setText("Eliminar transicion: "+_selectTransicion.toString());
				}else{
					_mnuEliminarEstado.setVisible(false);
					_mnuPropiedadesEstado.setVisible(false);
					_mnuEliminarTransicion.setVisible(false);
				}
				_menu.show(FSMPanel.this, e.getX(), e.getY());
				return true;
			}else
				return false;
		}
	
	}
}
